#ifndef _NETWORK_INTERFACE_EXCEPTIONS_H_
#define _NETWORK_INTERFACE_EXCEPTIONS_H_

#include <buildspec.h>
#include <config.h>
#include <GSTenums.h>
#include <exceptions/GSTRuntimeException.h>
#include <Utils/GSTVersion.h>
#include <boost/lexical_cast.hpp>

#include <string>

namespace GST {

//prototypes:
namespace ClientUtils {
	class IDataTable;
	class FeatureClassDetailedDesc;
	class GeoColumnDesc; 
	struct FeatureDesc;
	class FeatureClassDesc;
}
namespace Geometry {
	class ClientGeometry;
}

//exceptions:
namespace exceptions 
{
	/**
		* Throw whenever it is not possible to use a connection.
		*/
	class NoConnection
		: public GSTRuntimeException
	{
	public:
		NoConnection(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{}
	};

	class ServerCrowded
		: public NoConnection
	{
	public:
		ServerCrowded(const std::string & throwLocation, const std::string& msg)
			: NoConnection(throwLocation,msg)
		{}
	};

	class NoAdminConnection : public NoConnection
	{
	public:
		NoAdminConnection(const std::string &throwLocation,
						  const std::string &msg)
			: NoConnection(throwLocation, msg)
		{
		}
	};

	/**
		* thrown on connect if the client is depreciated for the endpoint storage version.
		*/
	class ClientDeprecated
		: public GSTRuntimeException
	{
	public:
		ClientDeprecated(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	/**
		* thrown on connect if the backend (=gst storage) is depreciated for this version of client.
		*/
	class BackendDeprecated
		: public GSTRuntimeException
	{
	public:
		BackendDeprecated(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	class BackendAboveOrEqualRequired
		: public BackendDeprecated
	{
	public:

		Utils::GSTVersion minmalRequiredVersion;

		BackendAboveOrEqualRequired(const std::string & throwLocation, const std::string& msg, const Utils::GSTVersion & minmalRequiredVersion)
			: BackendDeprecated(throwLocation,msg)
			, minmalRequiredVersion(minmalRequiredVersion)
		{
		}

		virtual ~BackendAboveOrEqualRequired() throw() {}
	};

	class ServerInformationNotFound
		: public GSTRuntimeException
	{
	public:
		ServerInformationNotFound(const std::string & throwLocation)
			: GSTRuntimeException(throwLocation,"Relation server_information not found. Create one!")
		{}
	};

	class UpdateFailed
		: public GSTRuntimeException
	{
	public:
		UpdateFailed(const std::string & throwLocation, const std::string msg)
			: GSTRuntimeException(throwLocation,msg)
		{}
	};

	class InsertFailed
		: public GSTRuntimeException
	{
	public:
		InsertFailed(const std::string & throwLocation, const std::string msg)
			: GSTRuntimeException(throwLocation,msg)
		{}
	};

	class FeatureClassCreationFailed
		: public GSTRuntimeException
	{
	public:
		FeatureClassCreationFailed(const std::string & throwLocation, const std::string msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	class FeatureClassDoesNotExist
		: public GSTRuntimeException
	{
	public:
		FeatureClassDoesNotExist(const std::string & throwLocation, const std::string& fclass)
			: GSTRuntimeException(throwLocation,"")
		{
			this->_msg = "FeatureDesc class " + fclass + " does not exist.";
		}
	};

	class LockKeyDoesNotExist
		: public GSTRuntimeException
	{
	public:
		std::string lockKey;

		LockKeyDoesNotExist(const std::string & throwLocation, const std::string & msg, const std::string & lockKey)
			: GSTRuntimeException(throwLocation,msg)
			, lockKey(lockKey)
		{ 
		}
		virtual ~LockKeyDoesNotExist() throw() {}
	};

	class FeatureHasNoPropertyTable
		: public GSTRuntimeException
	{
	public:
		FeatureHasNoPropertyTable(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	class ViolateConvention
		: public GSTRuntimeException
	{
	public:
		ViolateConvention(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	class NotAssigned
		: public GSTRuntimeException
	{
	public:
		NotAssigned(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	class DuplicateName
		: public GSTRuntimeException
	{
	public:
		DuplicateName(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{
		}
	};

	class NameAlreadyExists
		: public GSTRuntimeException
	{
	public:
		
		std::string suggestedName;

		NameAlreadyExists(const std::string & throwLocation, const std::string& msg, const std::string uniqueName)
			: GSTRuntimeException(throwLocation,msg)
			, suggestedName(uniqueName)
		{
		}
		
		virtual ~NameAlreadyExists() throw() {}
	};

	class NotFound
		: public GSTRuntimeException
	{
	public:
		NotFound(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation, msg)
		{
		}
	};

	class GeometryTypeUnkown
		: public GSTRuntimeException
	{
	public:
		GeometryTypeUnkown(const std::string & throwLocation, Geometry::GeometryTypes type)
			: GSTRuntimeException(throwLocation,"")
		{
			this->_msg = "Geometry type \""+boost::lexical_cast<std::string>(type)+"\" unknown.";
		}
	};

	class AlignmentTypeUnkown
		: public GSTRuntimeException
	{
	public:
		AlignmentTypeUnkown(const std::string & throwLocation, Geometry::PropertyAlignments type)
			: GSTRuntimeException(throwLocation,"")
		{
			this->_msg = "Alignment type \""+boost::lexical_cast<std::string>(type)+"\" unknown.";
		}
	};

	/** 
	 * Thrown if result set is invalid.
	 */
	class BadResultsetException
		: public GSTRuntimeException
	{
	public:
		BadResultsetException(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{}
	};

	/** 
	 * Thrown on accessing data from table if cell identifer is out of range.
	 * Example: The given (row,col) pair does not exist in table.
	 */
	class InvalidCellKey
		: public GSTRuntimeException
	{
	public:
		InvalidCellKey(const std::string & throwLocation, const std::string& msg)
			: GSTRuntimeException(throwLocation,msg)
		{}
	};

	/** 
	 * Thrown on accessing data from table if cell is null value.
	 * Prevent this by call isNull before get value.
	 */
	class IsNull
		: public GSTRuntimeException
	{
	public:
		std::string colName;
		int colNumber;

		IsNull(const std::string & throwLocation, const std::string & colName, int col)
			: GSTRuntimeException(throwLocation,"")
			, colName(colName)
			, colNumber(col)
		{
			_msg = "Value of "+colName+" (col num: "+boost::lexical_cast<std::string>(col)+") is null.";
		}
		~IsNull() throw() {}
	};

	/** 
	 * Thrown on accessing data from table if requested return type does not exist.
	 * Try to use another type or add in derived class in getAs() the type you need!
	 */
	class UnregisteredType
		: public GSTRuntimeException
	{
	public:
		UnregisteredType(const std::string & throwLocation, const std::type_info& t)
			: GSTRuntimeException(throwLocation,"")
		{
			_msg = "type \""+std::string(t.name())+"\" not registered.";
		}
	};

}// namespace exceptions

} //namespace GST

#endif // _NETWORK_INTERFACE_EXCEPTIONS_H_